using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace MandelbrotExplorer
{
	/// <summary>
	/// Summary description for Form1.
	/// </summary>
	public class Form1 : System.Windows.Forms.Form
	{
        // Application furniture
        private System.Windows.Forms.PictureBox pictureBox1;
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.Label label2;
        private System.Windows.Forms.Label label3;
        private System.Windows.Forms.Label label4;
        private System.Windows.Forms.GroupBox groupBox1;
        private System.Windows.Forms.Button calculateButton;
        private System.Windows.Forms.TextBox leftTextBox;
        private System.Windows.Forms.TextBox bottomTextBox;
        private System.Windows.Forms.TextBox topTextBox;
        private System.Windows.Forms.TextBox rightTextBox;
        private System.Windows.Forms.ProgressBar progressBar;
        private System.Windows.Forms.TextBox iterationsTextBox;
        private System.Windows.Forms.Button backButton;
        private System.Windows.Forms.Button resetButton;

        // Selection rectangle
        private System.Drawing.Rectangle boundingRectangle;
        private System.Drawing.Pen boundingRectanglePen;

        // Calulation parameters
        private Fractal.Mandelbrot mandelbrot_;
        private Fractal.CalculationParameters cpCurrent;
        private Fractal.CalculationParameters cpNew;
        private Fractal.CalculationParameters cpPrevious;
        private System.Drawing.Image imageHome;
        private System.Drawing.Image imagePrevious;
        private System.Threading.Thread renderThread;
        private System.Windows.Forms.Button loadButton;
        private System.Windows.Forms.Button saveButton;
        private System.Windows.Forms.OpenFileDialog openFileDialog1;
        private System.Windows.Forms.SaveFileDialog saveFileDialog1;
        private System.Windows.Forms.CheckBox useIntervalCheckBox1;
        private System.Windows.Forms.Button zoomOutButton;
        private System.Windows.Forms.TextBox dimensionsTextBox;
        private System.Windows.Forms.Label label6;
        private System.Windows.Forms.Label label7;
        private System.Windows.Forms.NumericUpDown refreshPeriod;
        private System.Windows.Forms.CheckBox coloringControlCheckbox;
        private System.Windows.Forms.CheckBox grayscaleCheckbox;
        private System.Windows.Forms.Splitter splitter1;
        private System.Windows.Forms.Label label5;
        private System.Windows.Forms.Label label8;
        private System.Windows.Forms.TextBox juliaSeedReal;
        private System.Windows.Forms.TextBox juliaSeedImag;
        private System.Windows.Forms.GroupBox layout;
        private System.Windows.Forms.ComboBox fractalSelector;
        private System.Windows.Forms.CheckBox useIterationLimitCheckbox;

		/// <summary>   
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		public Form1()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();

            // Bounding rectange
            boundingRectanglePen = new Pen(
                new System.Drawing.Drawing2D.HatchBrush(
                    System.Drawing.Drawing2D.HatchStyle.WideDownwardDiagonal, 
                    System.Drawing.Color.Black, 
                    System.Drawing.Color.White));
            resetBoundingBox();

            cpCurrent = new Fractal.CalculationParameters();
            cpCurrent.left = -2;
            cpCurrent.right = 2;
            cpCurrent.top = 2;
            cpCurrent.bottom = -2;

            cpCurrent.iterations = 2500;

            cpCurrent.calculationType = Fractal.CalculationParameters.CalculationType.SinglePoint;

            cpNew = (Fractal.CalculationParameters)cpCurrent.Clone();

            iterationsTextBox.Text = Convert.ToString(cpCurrent.iterations);

            updateTextBoxes();

            updateDimensionsBox();

            imageHome = pictureBox1.Image;
       }

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
            System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Form1));
            this.pictureBox1 = new System.Windows.Forms.PictureBox();
            this.calculateButton = new System.Windows.Forms.Button();
            this.leftTextBox = new System.Windows.Forms.TextBox();
            this.label1 = new System.Windows.Forms.Label();
            this.label2 = new System.Windows.Forms.Label();
            this.label3 = new System.Windows.Forms.Label();
            this.label4 = new System.Windows.Forms.Label();
            this.bottomTextBox = new System.Windows.Forms.TextBox();
            this.topTextBox = new System.Windows.Forms.TextBox();
            this.rightTextBox = new System.Windows.Forms.TextBox();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.resetButton = new System.Windows.Forms.Button();
            this.backButton = new System.Windows.Forms.Button();
            this.loadButton = new System.Windows.Forms.Button();
            this.saveButton = new System.Windows.Forms.Button();
            this.zoomOutButton = new System.Windows.Forms.Button();
            this.dimensionsTextBox = new System.Windows.Forms.TextBox();
            this.label6 = new System.Windows.Forms.Label();
            this.label7 = new System.Windows.Forms.Label();
            this.refreshPeriod = new System.Windows.Forms.NumericUpDown();
            this.progressBar = new System.Windows.Forms.ProgressBar();
            this.layout = new System.Windows.Forms.GroupBox();
            this.label8 = new System.Windows.Forms.Label();
            this.label5 = new System.Windows.Forms.Label();
            this.fractalSelector = new System.Windows.Forms.ComboBox();
            this.useIntervalCheckBox1 = new System.Windows.Forms.CheckBox();
            this.iterationsTextBox = new System.Windows.Forms.TextBox();
            this.coloringControlCheckbox = new System.Windows.Forms.CheckBox();
            this.grayscaleCheckbox = new System.Windows.Forms.CheckBox();
            this.useIterationLimitCheckbox = new System.Windows.Forms.CheckBox();
            this.juliaSeedReal = new System.Windows.Forms.TextBox();
            this.juliaSeedImag = new System.Windows.Forms.TextBox();
            this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
            this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog();
            this.splitter1 = new System.Windows.Forms.Splitter();
            this.groupBox1.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.refreshPeriod)).BeginInit();
            this.layout.SuspendLayout();
            this.SuspendLayout();
            // 
            // pictureBox1
            // 
            this.pictureBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
                | System.Windows.Forms.AnchorStyles.Left) 
                | System.Windows.Forms.AnchorStyles.Right)));
            this.pictureBox1.BackColor = System.Drawing.Color.Black;
            this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));
            this.pictureBox1.Location = new System.Drawing.Point(8, 8);
            this.pictureBox1.Name = "pictureBox1";
            this.pictureBox1.Size = new System.Drawing.Size(600, 600);
            this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
            this.pictureBox1.TabIndex = 0;
            this.pictureBox1.TabStop = false;
            this.pictureBox1.Resize += new System.EventHandler(this.pictureBox1_Resize);
            this.pictureBox1.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint);
            this.pictureBox1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.pictureBox1_MouseUp);
            this.pictureBox1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.pictureBox1_MouseMove);
            this.pictureBox1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.pictureBox1_MouseDown);
            // 
            // calculateButton
            // 
            this.calculateButton.Anchor = System.Windows.Forms.AnchorStyles.Top;
            this.calculateButton.Location = new System.Drawing.Point(152, 72);
            this.calculateButton.Name = "calculateButton";
            this.calculateButton.Size = new System.Drawing.Size(136, 64);
            this.calculateButton.TabIndex = 1;
            this.calculateButton.Text = "Go";
            this.calculateButton.Click += new System.EventHandler(this.calculateButton_Click);
            // 
            // leftTextBox
            // 
            this.leftTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.leftTextBox.Location = new System.Drawing.Point(8, 32);
            this.leftTextBox.Name = "leftTextBox";
            this.leftTextBox.Size = new System.Drawing.Size(136, 20);
            this.leftTextBox.TabIndex = 1;
            this.leftTextBox.Text = "";
            this.leftTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
            // 
            // label1
            // 
            this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.label1.Location = new System.Drawing.Point(8, 16);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(48, 16);
            this.label1.TabIndex = 3;
            this.label1.Text = "Left";
            this.label1.TextAlign = System.Drawing.ContentAlignment.BottomLeft;
            // 
            // label2
            // 
            this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.label2.Location = new System.Drawing.Point(152, 56);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(80, 16);
            this.label2.TabIndex = 4;
            this.label2.Text = "Bottom";
            this.label2.TextAlign = System.Drawing.ContentAlignment.BottomLeft;
            // 
            // label3
            // 
            this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.label3.Location = new System.Drawing.Point(8, 56);
            this.label3.Name = "label3";
            this.label3.Size = new System.Drawing.Size(104, 16);
            this.label3.TabIndex = 5;
            this.label3.Text = "Top";
            this.label3.TextAlign = System.Drawing.ContentAlignment.BottomLeft;
            // 
            // label4
            // 
            this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.label4.Location = new System.Drawing.Point(152, 16);
            this.label4.Name = "label4";
            this.label4.Size = new System.Drawing.Size(56, 16);
            this.label4.TabIndex = 6;
            this.label4.Text = "Right";
            this.label4.TextAlign = System.Drawing.ContentAlignment.BottomLeft;
            // 
            // bottomTextBox
            // 
            this.bottomTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.bottomTextBox.Cursor = System.Windows.Forms.Cursors.Default;
            this.bottomTextBox.Enabled = false;
            this.bottomTextBox.ForeColor = System.Drawing.SystemColors.WindowText;
            this.bottomTextBox.Location = new System.Drawing.Point(152, 72);
            this.bottomTextBox.Name = "bottomTextBox";
            this.bottomTextBox.Size = new System.Drawing.Size(136, 20);
            this.bottomTextBox.TabIndex = 4;
            this.bottomTextBox.Text = "";
            this.bottomTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
            // 
            // topTextBox
            // 
            this.topTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.topTextBox.Location = new System.Drawing.Point(8, 72);
            this.topTextBox.Name = "topTextBox";
            this.topTextBox.Size = new System.Drawing.Size(136, 20);
            this.topTextBox.TabIndex = 3;
            this.topTextBox.Text = "";
            this.topTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
            // 
            // rightTextBox
            // 
            this.rightTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.rightTextBox.Location = new System.Drawing.Point(152, 32);
            this.rightTextBox.Name = "rightTextBox";
            this.rightTextBox.Size = new System.Drawing.Size(136, 20);
            this.rightTextBox.TabIndex = 2;
            this.rightTextBox.Text = "";
            this.rightTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
            // 
            // groupBox1
            // 
            this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.groupBox1.Controls.Add(this.leftTextBox);
            this.groupBox1.Controls.Add(this.label1);
            this.groupBox1.Controls.Add(this.label2);
            this.groupBox1.Controls.Add(this.label3);
            this.groupBox1.Controls.Add(this.label4);
            this.groupBox1.Controls.Add(this.bottomTextBox);
            this.groupBox1.Controls.Add(this.topTextBox);
            this.groupBox1.Controls.Add(this.rightTextBox);
            this.groupBox1.Controls.Add(this.resetButton);
            this.groupBox1.Controls.Add(this.backButton);
            this.groupBox1.Controls.Add(this.loadButton);
            this.groupBox1.Controls.Add(this.saveButton);
            this.groupBox1.Controls.Add(this.zoomOutButton);
            this.groupBox1.Controls.Add(this.dimensionsTextBox);
            this.groupBox1.Controls.Add(this.label6);
            this.groupBox1.Controls.Add(this.label7);
            this.groupBox1.Controls.Add(this.refreshPeriod);
            this.groupBox1.Location = new System.Drawing.Point(616, 8);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(296, 208);
            this.groupBox1.TabIndex = 10;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "Boundary";
            this.groupBox1.TextChanged += new System.EventHandler(this.changeFractalType);
            // 
            // resetButton
            // 
            this.resetButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.resetButton.Location = new System.Drawing.Point(104, 144);
            this.resetButton.Name = "resetButton";
            this.resetButton.Size = new System.Drawing.Size(88, 24);
            this.resetButton.TabIndex = 1;
            this.resetButton.Text = "Home";
            this.resetButton.Click += new System.EventHandler(this.resetButton_Click);
            // 
            // backButton
            // 
            this.backButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.backButton.Enabled = false;
            this.backButton.Location = new System.Drawing.Point(8, 144);
            this.backButton.Name = "backButton";
            this.backButton.Size = new System.Drawing.Size(88, 24);
            this.backButton.TabIndex = 1;
            this.backButton.Text = "Back";
            this.backButton.Click += new System.EventHandler(this.restorePrevious_Click);
            // 
            // loadButton
            // 
            this.loadButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.loadButton.Location = new System.Drawing.Point(8, 176);
            this.loadButton.Name = "loadButton";
            this.loadButton.Size = new System.Drawing.Size(136, 24);
            this.loadButton.TabIndex = 1;
            this.loadButton.Text = "Load";
            this.loadButton.Click += new System.EventHandler(this.loadButton_Click);
            // 
            // saveButton
            // 
            this.saveButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.saveButton.Location = new System.Drawing.Point(152, 176);
            this.saveButton.Name = "saveButton";
            this.saveButton.Size = new System.Drawing.Size(136, 24);
            this.saveButton.TabIndex = 1;
            this.saveButton.Text = "Save";
            this.saveButton.Click += new System.EventHandler(this.saveButton_Click);
            // 
            // zoomOutButton
            // 
            this.zoomOutButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.zoomOutButton.Location = new System.Drawing.Point(200, 144);
            this.zoomOutButton.Name = "zoomOutButton";
            this.zoomOutButton.Size = new System.Drawing.Size(88, 24);
            this.zoomOutButton.TabIndex = 1;
            this.zoomOutButton.Text = "Zoom Out";
            this.zoomOutButton.Click += new System.EventHandler(this.zoomOutButton_Click);
            // 
            // dimensionsTextBox
            // 
            this.dimensionsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.dimensionsTextBox.Cursor = System.Windows.Forms.Cursors.Default;
            this.dimensionsTextBox.Enabled = false;
            this.dimensionsTextBox.ForeColor = System.Drawing.SystemColors.WindowText;
            this.dimensionsTextBox.Location = new System.Drawing.Point(152, 112);
            this.dimensionsTextBox.Name = "dimensionsTextBox";
            this.dimensionsTextBox.Size = new System.Drawing.Size(136, 20);
            this.dimensionsTextBox.TabIndex = 5;
            this.dimensionsTextBox.Text = "";
            this.dimensionsTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
            // 
            // label6
            // 
            this.label6.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.label6.Location = new System.Drawing.Point(152, 96);
            this.label6.Name = "label6";
            this.label6.Size = new System.Drawing.Size(104, 16);
            this.label6.TabIndex = 4;
            this.label6.Text = "Dimensions";
            this.label6.TextAlign = System.Drawing.ContentAlignment.BottomLeft;
            // 
            // label7
            // 
            this.label7.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.label7.Location = new System.Drawing.Point(8, 96);
            this.label7.Name = "label7";
            this.label7.Size = new System.Drawing.Size(104, 16);
            this.label7.TabIndex = 5;
            this.label7.Text = "Refresh (seconds)";
            this.label7.TextAlign = System.Drawing.ContentAlignment.BottomLeft;
            // 
            // refreshPeriod
            // 
            this.refreshPeriod.Location = new System.Drawing.Point(8, 112);
            this.refreshPeriod.Name = "refreshPeriod";
            this.refreshPeriod.Size = new System.Drawing.Size(136, 20);
            this.refreshPeriod.TabIndex = 13;
            this.refreshPeriod.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
            this.refreshPeriod.Value = new System.Decimal(new int[] {
                                                                        2,
                                                                        0,
                                                                        0,
                                                                        0});
            // 
            // progressBar
            // 
            this.progressBar.Anchor = System.Windows.Forms.AnchorStyles.Top;
            this.progressBar.Location = new System.Drawing.Point(8, 144);
            this.progressBar.Name = "progressBar";
            this.progressBar.Size = new System.Drawing.Size(280, 24);
            this.progressBar.TabIndex = 11;
            // 
            // layout
            // 
            this.layout.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.layout.Controls.Add(this.label8);
            this.layout.Controls.Add(this.label5);
            this.layout.Controls.Add(this.fractalSelector);
            this.layout.Controls.Add(this.useIntervalCheckBox1);
            this.layout.Controls.Add(this.iterationsTextBox);
            this.layout.Controls.Add(this.calculateButton);
            this.layout.Controls.Add(this.progressBar);
            this.layout.Controls.Add(this.coloringControlCheckbox);
            this.layout.Controls.Add(this.grayscaleCheckbox);
            this.layout.Controls.Add(this.useIterationLimitCheckbox);
            this.layout.Controls.Add(this.juliaSeedReal);
            this.layout.Controls.Add(this.juliaSeedImag);
            this.layout.Location = new System.Drawing.Point(616, 216);
            this.layout.Name = "layout";
            this.layout.Size = new System.Drawing.Size(296, 176);
            this.layout.TabIndex = 12;
            this.layout.TabStop = false;
            this.layout.Text = "Calculation";
            // 
            // label8
            // 
            this.label8.Location = new System.Drawing.Point(128, 72);
            this.label8.Name = "label8";
            this.label8.Size = new System.Drawing.Size(16, 16);
            this.label8.TabIndex = 15;
            this.label8.Text = "i";
            this.label8.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
            // 
            // label5
            // 
            this.label5.Location = new System.Drawing.Point(56, 72);
            this.label5.Name = "label5";
            this.label5.Size = new System.Drawing.Size(24, 16);
            this.label5.TabIndex = 14;
            this.label5.Text = "+";
            this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
            // 
            // fractalSelector
            // 
            this.fractalSelector.Items.AddRange(new object[] {
                                                                 "Mandelbrot",
                                                                 "Julia"});
            this.fractalSelector.Location = new System.Drawing.Point(8, 40);
            this.fractalSelector.Name = "fractalSelector";
            this.fractalSelector.Size = new System.Drawing.Size(136, 21);
            this.fractalSelector.TabIndex = 13;
            this.fractalSelector.Text = "Mandelbrot";
            this.fractalSelector.TextChanged += new System.EventHandler(this.changeFractalType);
            // 
            // useIntervalCheckBox1
            // 
            this.useIntervalCheckBox1.Checked = true;
            this.useIntervalCheckBox1.CheckState = System.Windows.Forms.CheckState.Checked;
            this.useIntervalCheckBox1.Location = new System.Drawing.Point(8, 16);
            this.useIntervalCheckBox1.Name = "useIntervalCheckBox1";
            this.useIntervalCheckBox1.Size = new System.Drawing.Size(120, 24);
            this.useIntervalCheckBox1.TabIndex = 12;
            this.useIntervalCheckBox1.Text = "Use intervals";
            this.useIntervalCheckBox1.CheckedChanged += new System.EventHandler(this.updateIterationsCheckbox);
            // 
            // iterationsTextBox
            // 
            this.iterationsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.iterationsTextBox.Cursor = System.Windows.Forms.Cursors.Default;
            this.iterationsTextBox.Enabled = false;
            this.iterationsTextBox.ForeColor = System.Drawing.SystemColors.WindowText;
            this.iterationsTextBox.Location = new System.Drawing.Point(152, 40);
            this.iterationsTextBox.Name = "iterationsTextBox";
            this.iterationsTextBox.Size = new System.Drawing.Size(136, 20);
            this.iterationsTextBox.TabIndex = 7;
            this.iterationsTextBox.Text = "";
            this.iterationsTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
            // 
            // coloringControlCheckbox
            // 
            this.coloringControlCheckbox.Location = new System.Drawing.Point(8, 120);
            this.coloringControlCheckbox.Name = "coloringControlCheckbox";
            this.coloringControlCheckbox.Size = new System.Drawing.Size(120, 24);
            this.coloringControlCheckbox.TabIndex = 12;
            this.coloringControlCheckbox.Text = "Smooth coloring";
            // 
            // grayscaleCheckbox
            // 
            this.grayscaleCheckbox.Location = new System.Drawing.Point(8, 96);
            this.grayscaleCheckbox.Name = "grayscaleCheckbox";
            this.grayscaleCheckbox.Size = new System.Drawing.Size(120, 24);
            this.grayscaleCheckbox.TabIndex = 12;
            this.grayscaleCheckbox.Text = "Simple grayscale";
            // 
            // useIterationLimitCheckbox
            // 
            this.useIterationLimitCheckbox.Location = new System.Drawing.Point(152, 16);
            this.useIterationLimitCheckbox.Name = "useIterationLimitCheckbox";
            this.useIterationLimitCheckbox.Size = new System.Drawing.Size(120, 24);
            this.useIterationLimitCheckbox.TabIndex = 12;
            this.useIterationLimitCheckbox.Text = "Iteration limit";
            this.useIterationLimitCheckbox.CheckedChanged += new System.EventHandler(this.updateIterationsCheckbox);
            // 
            // juliaSeedReal
            // 
            this.juliaSeedReal.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.juliaSeedReal.Enabled = false;
            this.juliaSeedReal.Location = new System.Drawing.Point(8, 72);
            this.juliaSeedReal.Name = "juliaSeedReal";
            this.juliaSeedReal.Size = new System.Drawing.Size(48, 20);
            this.juliaSeedReal.TabIndex = 2;
            this.juliaSeedReal.Text = "-0.123";
            this.juliaSeedReal.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
            // 
            // juliaSeedImag
            // 
            this.juliaSeedImag.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.juliaSeedImag.Enabled = false;
            this.juliaSeedImag.Location = new System.Drawing.Point(80, 72);
            this.juliaSeedImag.Name = "juliaSeedImag";
            this.juliaSeedImag.Size = new System.Drawing.Size(48, 20);
            this.juliaSeedImag.TabIndex = 2;
            this.juliaSeedImag.Text = "0.745";
            this.juliaSeedImag.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
            // 
            // openFileDialog1
            // 
            this.openFileDialog1.Filter = "XML files|*.xml";
            // 
            // saveFileDialog1
            // 
            this.saveFileDialog1.DefaultExt = "xml";
            this.saveFileDialog1.Filter = "XML files|*.xml";
            // 
            // splitter1
            // 
            this.splitter1.Location = new System.Drawing.Point(0, 0);
            this.splitter1.Name = "splitter1";
            this.splitter1.Size = new System.Drawing.Size(8, 614);
            this.splitter1.TabIndex = 13;
            this.splitter1.TabStop = false;
            // 
            // Form1
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(920, 614);
            this.Controls.Add(this.splitter1);
            this.Controls.Add(this.layout);
            this.Controls.Add(this.groupBox1);
            this.Controls.Add(this.pictureBox1);
            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
            this.Name = "Form1";
            this.Text = "Interval Mandelbrot";
            this.Closing += new System.ComponentModel.CancelEventHandler(this.Form1_Closing);
            this.groupBox1.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)(this.refreshPeriod)).EndInit();
            this.layout.ResumeLayout(false);
            this.ResumeLayout(false);

        }
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			Application.Run(new Form1());
		}

        // GUI methods
        private void updateCalculationBottom()
        {
            // Bottom is adjusted to maintain aspect ratio
            double a = Convert.ToDouble(pictureBox1.Height) / Convert.ToDouble(pictureBox1.Width);
            cpNew.bottom = cpNew.top - a * cpNew.getWidth();
        }

        // GUI methods
        private void updateTextBoxes()
        {
            // Calculate extents of the bounding rectangle
            cpNew.left   = cpCurrent.left + Convert.ToDouble(boundingRectangle.Left)   * cpCurrent.getWidth()  / Convert.ToDouble(pictureBox1.Width);
            cpNew.right  = cpCurrent.left + Convert.ToDouble(boundingRectangle.Right)  * cpCurrent.getWidth()  / Convert.ToDouble(pictureBox1.Width);
            cpNew.top    = cpCurrent.top  - Convert.ToDouble(boundingRectangle.Top)    * cpCurrent.getHeight() / Convert.ToDouble(pictureBox1.Height);
            updateCalculationBottom();
            // Update GUI text boxes
            leftTextBox.Text = Convert.ToString(cpNew.left);
            rightTextBox.Text = Convert.ToString(cpNew.right);
            topTextBox.Text = Convert.ToString(cpNew.top);
            bottomTextBox.Text = Convert.ToString(cpNew.bottom);
            iterationsTextBox.Text = Convert.ToString(cpNew.iterations);
        }

        // Bounding box methods

        private void pictureBox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
            g.DrawRectangle(boundingRectanglePen, boundingRectangle);        
        }

        private void resetButton_Click(object sender, System.EventArgs e)
        {
            cpCurrent.left = -2;
            cpCurrent.right = 2;
            cpCurrent.top = 2;
            cpCurrent.bottom = -2;
            pictureBox1.Image = imageHome;
            resetBoundingBox();
            updateTextBoxes();
        }

        private void restorePrevious_Click(object sender, System.EventArgs e)
        {
            // Swap 
            Fractal.CalculationParameters cpTemp = (Fractal.CalculationParameters)cpCurrent.Clone();
            cpCurrent = (Fractal.CalculationParameters)cpPrevious.Clone();
            cpPrevious = cpTemp;
            System.Drawing.Image imageTemp = (System.Drawing.Image)pictureBox1.Image.Clone();            
            pictureBox1.Image = imagePrevious;
            imagePrevious = imageTemp;
            resetBoundingBox();
            updateTextBoxes();
        }

        private void pictureBox1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            // Mouse is disabled if calculation is running
            if(renderThread == null)
            {
                if(e.Button == System.Windows.Forms.MouseButtons.Left)
                {
                    if(boundingRectangle.Width <= 0 || boundingRectangle.Height <= 0)
                    {
                        resetBoundingBox();
                        updateTextBoxes();
                    }
                }
            }
        }

        private void pictureBox1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
		{
            // Mouse is disabled if calculation is running
            if(renderThread == null)
            {
                if(e.Button == System.Windows.Forms.MouseButtons.Left)
                {
                    boundingRectangle.X = e.X;
                    boundingRectangle.Y = e.Y;
                    boundingRectangle.Width = 0;
                    boundingRectangle.Height = 0;
                    updateTextBoxes();
                    Refresh();
                }
                else if(e.Button == System.Windows.Forms.MouseButtons.Right)
                {
                    // Adjust julia seed
                    double x = cpCurrent.left + cpCurrent.getWidth() * Convert.ToDouble(e.X) / Convert.ToDouble(pictureBox1.Width);
                    double y = cpCurrent.top - cpCurrent.getHeight() * Convert.ToDouble(e.Y) / Convert.ToDouble(pictureBox1.Height);
                    juliaSeedReal.Text = x.ToString();
                    juliaSeedImag.Text = y.ToString(); 
                }
            }
		}

		private void pictureBox1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
		{
            // Mouse is disabled if calculation is running
            if(renderThread == null)
            {
                if(e.Button == System.Windows.Forms.MouseButtons.Left)
                {
                    // Adjust bounding rectange
                    boundingRectangle.Width = e.X - boundingRectangle.X;
                    boundingRectangle.Height = e.Y - boundingRectangle.Y;
                    updateTextBoxes();
                    Refresh();				
                }
            }
		}

        private void resetBoundingBox()
        {
            boundingRectangle = new System.Drawing.Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height);
            Refresh();
        }

        private System.DateTime lastUpdate_;
        private void renderUpdateCallback()
        {
            iterationsTextBox.Text = cpNew.iterations.ToString();
            progressBar.Value = mandelbrot_.getPixelsComplete();
            System.DateTime now = System.DateTime.Now;
            if(now - lastUpdate_ > System.TimeSpan.FromSeconds(System.Convert.ToDouble(refreshPeriod.Value)))
            {
                pictureBox1.Image = mandelbrot_.getBitmap();
                lastUpdate_ = now;
            }
        }

        private void renderCompleteCallback()
        {
            pictureBox1.Image = mandelbrot_.getBitmap();
            updateTextBoxes();
            calculateButton.Enabled = true;
            renderThread = null;
            calculateButton.Text = "Go";
        }

        private void calculateButton_Click(object sender, System.EventArgs e)
        {
            // Is the calculation running?
            if(renderThread != null)
            {
                renderThread.Abort();
                renderThread = null;
                calculateButton.Text = "Go";
                progressBar.Value = 0;
                return;
            }
            // Reset update timer
            lastUpdate_ = System.DateTime.FromOADate(0);
            // Store old calculation parameters and bitmap
            cpPrevious = (Fractal.CalculationParameters)cpCurrent.Clone();
            imagePrevious = pictureBox1.Image;
            backButton.Enabled = true;

            // Update calculation parameters

            // Limits may have been edited directly
            cpNew.left  = Convert.ToDouble(leftTextBox.Text);
            cpNew.right = Convert.ToDouble(rightTextBox.Text);
            cpNew.top   = Convert.ToDouble(topTextBox.Text);
            updateCalculationBottom();

            cpNew.pixelWidth = pictureBox1.Width;
            cpNew.pixelHeight = pictureBox1.Height;

            cpNew.useIterationLimit = useIterationLimitCheckbox.Checked;
            cpNew.iterations = System.Convert.ToUInt32(iterationsTextBox.Text);

            if(fractalSelector.Text == "Mandelbrot")
            {
                cpNew.fractalType = Fractal.CalculationParameters.FractalType.Mandelbrot;
            }
            else
            {
                cpNew.fractalType = Fractal.CalculationParameters.FractalType.Julia;
            }

            cpNew.juliaReal = Convert.ToDouble(juliaSeedReal.Text);
            cpNew.juliaImag = Convert.ToDouble(juliaSeedImag.Text);

            if(useIntervalCheckBox1.Checked)
            {
                cpNew.calculationType = Fractal.CalculationParameters.CalculationType.Interval;
            }
            else
            {
                cpNew.calculationType = Fractal.CalculationParameters.CalculationType.SinglePoint;
            }

            cpNew.simpleGrayscale = grayscaleCheckbox.Checked;
            cpNew.smoothColoring = coloringControlCheckbox.Checked;

            progressBar.Value = 0;
            progressBar.Step = 1;
            progressBar.Maximum = pictureBox1.Height * pictureBox1.Width;

            calculateButton.Text = "Stop";

            // Store current calculation
            cpCurrent = (Fractal.CalculationParameters)cpNew.Clone();

            resetBoundingBox();

            // Calculation...
            mandelbrot_ = new Fractal.Mandelbrot(
                cpNew, 
                new System.Threading.ThreadStart(renderUpdateCallback),
                new System.Threading.ThreadStart(renderCompleteCallback));
            renderThread = new System.Threading.Thread(new System.Threading.ThreadStart(mandelbrot_.render));
            renderThread.Priority = System.Threading.ThreadPriority.Lowest;
            renderThread.Start();

        }

        private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if(renderThread != null)
            {
                renderThread.Abort();
            }        
        }

        private void loadButton_Click(object sender, System.EventArgs e)
        {
            System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
            if(openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                try
                {
                    xmlDoc.Load(openFileDialog1.FileName);
                }
                catch(System.Exception exeception)
                {
                    System.Windows.Forms.MessageBox.Show(
                        exeception.Message, 
                        "Error loading boundary", 
                        System.Windows.Forms.MessageBoxButtons.OK, 
                        System.Windows.Forms.MessageBoxIcon.Error);
                    return;
                }
                // Fractal type
                System.Xml.XmlNode fractalTypeNode = xmlDoc.SelectSingleNode("fractal/@type");
                if(fractalTypeNode != null)
                {
                    fractalSelector.Text = fractalTypeNode.InnerText;
                }
                // Julia
                System.Xml.XmlNode juliaRealNode = xmlDoc.SelectSingleNode("//julia/real");
                if(juliaRealNode != null)
                {
                    juliaSeedReal.Text = juliaRealNode.InnerText;
                }
                System.Xml.XmlNode juliaImagNode = xmlDoc.SelectSingleNode("//julia/imag");
                if(juliaImagNode != null)
                {
                    juliaSeedImag.Text = juliaImagNode.InnerText;
                }
                // Boundary
                System.Xml.XmlNode boundaryNode = xmlDoc.SelectSingleNode("//boundary");
                if(boundaryNode != null)
                {
                    System.Xml.XmlNode leftNode = boundaryNode.SelectSingleNode("left");
                    System.Xml.XmlNode rightNode = boundaryNode.SelectSingleNode("right");
                    System.Xml.XmlNode topNode = boundaryNode.SelectSingleNode("top");
                    System.Xml.XmlNode bottomNode = boundaryNode.SelectSingleNode("bottom");
                    if(leftNode != null && rightNode != null && topNode != null)
                    {
                        cpCurrent.left = Convert.ToDouble(leftNode.InnerText);
                        cpCurrent.right = Convert.ToDouble(rightNode.InnerText);
                        cpCurrent.top = Convert.ToDouble(topNode.InnerText);
                        // Bottom definition is optional
                        if(bottomNode != null)
                        {
                            cpCurrent.bottom = Convert.ToDouble(bottomNode.InnerText);
                        }
                        updateTextBoxes();
                        resetBoundingBox();
                        return;
                    }
                }
                // If control reaches this point, a formatting error has occured
                System.Windows.Forms.MessageBox.Show(
                    xmlDoc.OuterXml, 
                    "Invalid format", 
                    System.Windows.Forms.MessageBoxButtons.OK, 
                    System.Windows.Forms.MessageBoxIcon.Error);
            }
        }

        private void saveButton_Click(object sender, System.EventArgs e)
        {
            System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
            if(saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                // Fractal node
                xmlDoc.LoadXml("<fractal/>");
                System.Xml.XmlNode fractalNode = xmlDoc.DocumentElement;
                // Fractal type
                System.Xml.XmlAttribute typeNode = xmlDoc.CreateAttribute("type");
                typeNode.InnerText = fractalSelector.Text;
                fractalNode.Attributes.Append(typeNode);
                // Julia specific
                System.Xml.XmlNode juliaNode = fractalNode.AppendChild(xmlDoc.CreateElement("julia"));
                juliaNode.AppendChild(xmlDoc.CreateElement("real")).InnerText = juliaSeedReal.Text;
                juliaNode.AppendChild(xmlDoc.CreateElement("imag")).InnerText = juliaSeedImag.Text;
                // Boundary
                System.Xml.XmlNode boundaryNode = fractalNode.AppendChild(xmlDoc.CreateElement("boundary"));
                boundaryNode.AppendChild(xmlDoc.CreateElement("left")).InnerText = cpCurrent.left.ToString();
                boundaryNode.AppendChild(xmlDoc.CreateElement("right")).InnerText = cpCurrent.right.ToString();
                boundaryNode.AppendChild(xmlDoc.CreateElement("top")).InnerText = cpCurrent.top.ToString();
                boundaryNode.AppendChild(xmlDoc.CreateElement("bottom")).InnerText = cpCurrent.bottom.ToString();
                xmlDoc.Save(saveFileDialog1.FileName);
                // Save image
                if(pictureBox1.Image != null)
                {
                    string bitmapFilename = saveFileDialog1.FileName.Substring(0, saveFileDialog1.FileName.LastIndexOf("."))
                        + ".bmp";
                    pictureBox1.Image.Save(bitmapFilename);
                }
            }
        }

        private void zoomOutButton_Click(object sender, System.EventArgs e)
        {
            double halfWidth = (cpCurrent.right - cpCurrent.left) / 2.0;
            cpCurrent.left -= halfWidth;
            cpCurrent.right += halfWidth;
            cpCurrent.top += halfWidth;
            cpCurrent.bottom -= halfWidth;
            resetBoundingBox();
            updateTextBoxes();
        }

        private void updateIterationsCheckbox(object sender, System.EventArgs e)
        {
            if(useIntervalCheckBox1.Checked)
            {
                useIterationLimitCheckbox.Enabled = true;
                if(useIterationLimitCheckbox.Checked)
                {
                    iterationsTextBox.Enabled = true;
                }
                else
                {
                    iterationsTextBox.Enabled = false;
                }
            }
            else
            {
                useIterationLimitCheckbox.Enabled = false;
                iterationsTextBox.Enabled = true;
            }
        }

        private void updateDimensionsBox()
        {
            dimensionsTextBox.Text = pictureBox1.Width.ToString() + ", " + pictureBox1.Height.ToString();
        }

        private void pictureBox1_Resize(object sender, System.EventArgs e)
        {
            updateDimensionsBox();
        }

        private void changeFractalType(object sender, System.EventArgs e)
        {
            if(fractalSelector.Text == "Mandelbrot")
            {
                juliaSeedReal.Enabled = false;
                juliaSeedImag.Enabled = false;
            }
            else
            {
                juliaSeedReal.Enabled = true;
                juliaSeedImag.Enabled = true;
            }
        }

    }
}
